﻿using System.Collections.Generic;
using Windows.UI.Xaml.Controls;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace InspirationNote.Core
{
    using System;
    using System.Collections.ObjectModel;
    using Windows.UI;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Data;
    using static HSLHelper;

    public struct HSL
    {
        public float Hue { get; set; }
        public float Saturation { get; set; }
        public float Luminance { get; set; }
    }

    public static class HSLHelper
    {
        #region HSL2RGB

        public static Color Hsl2Rgb(float hue, float saturation, float luminance)
        {
            var q  = ComputeQ(luminance,saturation);
            var p = 2 * luminance - q;
            var Hk = ComputeHk(hue);
            var tR = Clamp(ComputeTr(Hk));
            var tG = Clamp(ComputeTg(Hk));
            var tB = Clamp(ComputeTb(Hk));

            var r = (ComputeColor_C(tR, p, q) * 255);
            var g = (ComputeColor_C(tG, p, q) * 255);
            var b = (ComputeColor_C(tB, p, q) * 255);
            return new Color()
            {
                R = (byte)r,
                G = (byte)g,
                B = (byte)b,
                A = 255
            };
        }

        static float ComputeQ(float l, float s)
        {
            if (l < .5f) {
                return l * (1.0f + s);
            }
            else {
                return l + s - (l * s);
            }
        }

        static float ComputeP(float l, float q) => 2.0f * l - q;

        static float ComputeHk(float h) => h / 360f;

        static float ComputeTr(float Hk) => Hk + .33f;

        static float ComputeTg(float Hk) => Hk;

        static float ComputeTb(float Hk) => Hk - .33333333f;

        static float Clamp(float tc)
        {
            if (tc < 0) {
                return tc + 1.0f;
            }
            else if (tc > 1.0) {
                return tc - 1.0f;
            }
            return tc;
        }

        static float ComputeColor_C(float tc, float p, float q)
        {
            if (tc < .1666f) {
                return p + ((q - p) * 6 * tc);
            }
            else if (tc > .1666f && tc < .5f) {
                return q;
            }
            else if (tc > .5f && tc < .6667f) {
                return p + ((q - p) * 6 * (.6667f - tc));
            }
            else {
                return p;
            }
        }

        #endregion

        #region RGB2HSL

        public static HSL Rgb2Hsl(Color color)
        {
            var r = color.R;
            var g = color.G;
            var b = color.B;
            var max = ComputeMax(r,g,b);
            var min = ComputeMin(r,g,b);
            var l = ComputeL(min,max);
            return new HSL
            {
                Hue = ComputeH(r, g, b, max, min),
                Saturation = ComputeS(max, min, l),
                Luminance = l
            };
        }

        static float ComputeMax(float r, float g, float b)
        {
            var m1 = r > g ? r : g;
            var m2 = b > m1 ? b: m1;
            return m2;
        }

        static float ComputeMin(float r, float g, float b)
        {
            var m1 = r < g ? r : g;
            var m2 = b < m1 ? b: m1;
            return m2;
        }

        static float ComputeH(float r, float g, float b, float max, float min)
        {
            if (max == min) {
                return 0;
            }
            else if (max == r && g >= b) {
                return 60 * (g - b) / (max - min) + 0;
            }
            else if (max == r && g < b) {
                return 60 * (g - b) / (max - min) + 360;
            }
            else if (max == g) {
                return 60 * (b - r) / (max - min) + 120;
            }
            return 60 * (r - g) / (max - min) + 240;
        }

        static float ComputeL(float min, float max) => .5f * (max + min);

        static float ComputeS(float max, float min, float l)
        {
            if (l == 0 || max == min) {
                return 0;
            }
            else if (0 < l && l <= .5f) {
                return (max - min) / (2 * l);
            }
            return (max - min) / (2 - 2 * l);
        }

        #endregion

    }

    internal sealed class ColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if(value is Color c) {
                return new SolidColorBrush(c);
            }
            return new SolidColorBrush(Colors.Transparent);
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

    public sealed partial class ColorPalette : UserControl
    {

        #region ColorList

        readonly ObservableCollection<Color> C1 = new ObservableCollection<Color>
        {
            Hsl2Rgb(0,1.0f,.5f),
            Hsl2Rgb(0,.8f,.5f),
            Hsl2Rgb(0,.6f,.5f),
            Hsl2Rgb(0,.4f,.5f),
        };
        readonly ObservableCollection<Color> C2 = new ObservableCollection<Color>
        {
            Hsl2Rgb(60,1,.5f),
            Hsl2Rgb(60,.8f,.5f),
            Hsl2Rgb(60,.6f,.5f),
            Hsl2Rgb(60,.4f,.5f),
        };
        readonly ObservableCollection<Color> C3 = new ObservableCollection<Color>
        {
            Hsl2Rgb(120,1,.5f),
            Hsl2Rgb(120,.6f,.5f),
            Hsl2Rgb(120,.6f,.5f),
            Hsl2Rgb(120,.4f,.5f)
        };
        readonly ObservableCollection<Color> C4 = new ObservableCollection<Color>
        {
            Hsl2Rgb(180,1,.5f),
            Hsl2Rgb(180,.6f,.5f),
            Hsl2Rgb(180,.6f,.5f),
            Hsl2Rgb(180,.4f,.5f)
        };
        readonly ObservableCollection<Color> C5 = new ObservableCollection<Color>
        {
            Hsl2Rgb(240,1,.5f),
            Hsl2Rgb(240,.6f,.5f),
            Hsl2Rgb(240,.6f,.5f),
            Hsl2Rgb(240,.4f,.5f)
        };
        readonly ObservableCollection<Color> C6 = new ObservableCollection<Color>
        {
            Hsl2Rgb(300,1,.5f),
            Hsl2Rgb(300,.6f,.5f),
            Hsl2Rgb(300,.6f,.5f),
            Hsl2Rgb(300,.4f,.5f)
        };

        #endregion

        #region Red

        public ObservableCollection<Color> Red {
            get {
                return C1;
            }
        }

        #endregion

        #region Yellow

        public ObservableCollection<Color> Yellow {
            get {
                return C2;
            }
        }

        #endregion

        #region Green

        public ObservableCollection<Color> Green {
            get {
                return C3;
            }
        }

        #endregion

        #region Cyan

        public ObservableCollection<Color> Cyan {
            get {
                return C4;
            }
        }

        #endregion

        #region Blue

        public ObservableCollection<Color> Blue {
            get {
                return C5;
            }
        }

        #endregion

        #region Purple

        public ObservableCollection<Color> Purple {
            get {
                return C6;
            }
        }

        #endregion

        #region ColorRing

        public IReadOnlyCollection<HSL> ColorRing { get; private set; } = new ObservableCollection<HSL>
        {
            new HSL{ Hue = 0 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 60 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 120 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 180 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 240 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 300 ,Saturation = 1f , Luminance = .5f},
            new HSL{ Hue = 360 ,Saturation = 1f , Luminance = .5f}
        };

        #endregion

        public ColorPalette()
        {
            this.InitializeComponent();
        }
    }
}
